package com.jlf.starter.advice.reactive;

import com.jlf.core.output.ResultWrapper;
import com.jlf.starter.advice.reactive.util.OutputTool;
import lombok.SneakyThrows;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.web.reactive.HandlerResult;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;


/**
 * 统一输出的切面
 * 本方法的局限性太大：
 * 1、无法解决接口原型直接输出string的统一封装
 * 2、无法解决接口原型直接输出集合的统一封装
 *
 * @author wujr
 * 2023/8/2
 * @version 1.0
 * 【变更历史】
 * [wujr 2023/8/2 1.0 新增]
 */
@Deprecated
@Aspect
@ConditionalOnClass(name = {"org.springframework.web.reactive.result.method.annotation.ResponseBodyResultHandler"})
public class OutputAspect {
    @SneakyThrows
    @SuppressWarnings("unchecked")
    @Around(value = "execution(* org.springframework.web.reactive.result.method.annotation.ResponseBodyResultHandler.handleResult(..)) && args(exchange, result)", argNames = "point,exchange,result")
    public Object handleResult(ProceedingJoinPoint point, ServerWebExchange exchange, HandlerResult result) {
        if (!OutputTool.isSupported(result)) {
            return point.proceed(new Object[]{exchange, result});
        }
        Object resultValue = result.getReturnValue();
        final Object wrapperBody;
        // <1.1>  处理返回结果为 Mono 的情况
        if (resultValue instanceof Mono) {
            wrapperBody = ((Mono<Object>)resultValue).map(OutputTool::wrapResult);
            //  <1.2> 处理返回结果为 Flux 的情况
        } else if (resultValue instanceof Flux) {
            wrapperBody = ((Flux<Object>) resultValue).collectList()
                    .map(OutputTool::wrapResult);
            //  <1.3> 处理结果为其它类型
        }else if (resultValue instanceof ResultWrapper){
            wrapperBody = resultValue;
        } else {
            wrapperBody = OutputTool.wrapResult(resultValue);
        }
        final HandlerResult wrapperHandler = new HandlerResult(result.getHandler(), wrapperBody, result.getReturnTypeSource());
        return point.proceed(new Object[]{exchange, wrapperHandler});
    }

}
